﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SmartMathLibrary
{
    /// <summary>
    /// This class provides the scanning or sampling of a complex polynomial.
    /// </summary>
    [Serializable]
    public class ComplexPolynomialSampler : AbstractPolynomialSampler
    {
        /// <summary>
        /// The polynomial to scan.
        /// </summary>
        private ComplexPolynomial polynomial;

        /// <summary>
        /// Initializes a new instance of the <see cref="ComplexPolynomialSampler"/> class.
        /// </summary>
        /// <param name="polynomial">The polynomial to scan or sample.</param>
        public ComplexPolynomialSampler(ComplexPolynomial polynomial)
        {
            if (polynomial == (ComplexPolynomial) null)
            {
                throw new ArgumentNullException("polynomial");
            }

            this.polynomial = polynomial;
        }

        /// <summary>
        /// Gets or sets the polynomial to sample or scan.
        /// </summary>
        /// <value>The polynomial to sample or scan.</value>
        public ComplexPolynomial Polynomial
        {
            get { return polynomial; }
            set { polynomial = value; }
        }

        /// <summary>
        /// Samples or scans the polynomial in an specified interval.
        /// </summary>
        /// <param name="startValue">The start value of the sample process.</param>
        /// <param name="endValue">The end value of the sample process.</param>
        /// <param name="interval">The interval for the sampling process.</param>
        /// <returns>
        /// The results of the sampling process in form of plane points.
        /// </returns>
        public ComplexPoint2D[] SamplePolynomial(ComplexNumber startValue, ComplexNumber endValue,
                                                 ComplexNumber interval)
        {
            if ((endValue.RealNumberPart < startValue.RealNumberPart)
                && (endValue.ImaginaryNumberPart < startValue.ImaginaryNumberPart))
            {
                Swap(ref startValue, ref endValue);
            }

            if ((endValue.RealNumberPart == startValue.RealNumberPart)
                && (endValue.ImaginaryNumberPart < startValue.ImaginaryNumberPart))
            {
                Swap(ref startValue, ref endValue);
            }

            List<ComplexPoint2D> result = new List<ComplexPoint2D>();
            ComplexNumber workingValue = startValue.Copy();

            while (workingValue.RealNumberPart <= endValue.RealNumberPart)
            {
                result.Add(new ComplexPoint2D(workingValue, this.polynomial.SolveAt(workingValue)));
                workingValue += interval;
            }

            return result.ToArray();
        }

        /// <summary>
        /// Swaps the specified values.
        /// </summary>
        /// <param name="a">The first value to swap.</param>
        /// <param name="b">The second value to swap.</param>
        private static void Swap(ref ComplexNumber a, ref ComplexNumber b)
        {
            ComplexNumber tempuri = a;

            a = b;
            b = tempuri;
        }
    }
}